package org.bonn.ooka.core;

import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;

import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;

import org.w3c.dom.Document;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import org.xml.sax.SAXException;

public class XMLExtractor {
	private Document m_doc = null;

	public static XMLComponentMapping readStructure(String xmlPath) throws Exception {
		XMLExtractor xe = null;
		try {
			xe = new XMLExtractor(new File(xmlPath));
		} catch (Exception e) {
			throw new Exception("XML-Parsing Error");
		}

		return xe.readStructure(xe.m_doc);
	}

	private XMLExtractor(File xml) throws SAXException, IOException,
			ParserConfigurationException {
		DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
		DocumentBuilder db = dbf.newDocumentBuilder();

		Document doc = db.parse(xml);
		doc.normalize();

		this.m_doc = doc;
	}

	private XMLComponentMapping readStructure(Document doc) {
		Node mainCompNode = getMainComponent(doc.getChildNodes());

		XMLComponentMapping c = readComponent(mainCompNode);

		return c;
	}

	private XMLComponentMapping readComponent(Node n) {
		XMLComponentMapping c = new XMLComponentMapping();

		for (int i = 0; i < n.getChildNodes().getLength(); i++) {
			Node current = n.getChildNodes().item(i);

			switch (current.getNodeName()) {
			case "Name":
				c.name = readValue(current);
				break;
			case "Path":
				c.path = readValue(current);
				break;
			case "Class":
				c.classpath = readValue(current);
				break;
			case "Scope":
				c.scope = readValue(current);
				break;
			case "RequiredScope":
				c.required_scope = readValue(current);
				break;
			case "Dependencies":
				c.dependencies = readDependencies(current);
				break;
			}
		}

		return c;
	}

	private List<XMLComponentMapping> readDependencies(Node n) {
		List<Node> subs = readSubcomponents(n);

		return convertSubs(subs);
	}

	private List<XMLComponentMapping> convertSubs(List<Node> s) {
		List<XMLComponentMapping> subs = new ArrayList<>();
		
		for(Node n : s) {
			subs.add(readComponent(n));
		}
		
		return subs;
	}

	private List<Node> readSubcomponents(Node n) {
		List<Node> subs = new ArrayList<>();
		for (int i = 0; i < n.getChildNodes().getLength(); i++) {
			Node current = n.getChildNodes().item(i);

			if (current.getNodeName() == "SubComponent")
				subs.add(current);
		}
		
		return subs;
	}

	private String readValue(Node n) {
		Node child = n.getFirstChild();
		if (child == null)
			return "";

		return child.getNodeValue();
	}

	private Node getMainComponent(NodeList nodes) {
		for (int i = 0; i < nodes.getLength(); i++) {
			Node n = nodes.item(i);

			if (n.getNodeName() == "MainComponent")
				return n;

			Node tmp = getMainComponent(n.getChildNodes());
			if (tmp != null)
				return tmp;
		}

		return null;
	}

}
